package net.stevechaloner.idea.ffs.config;

import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import net.stevechaloner.idea.ffs.SearchProviderProvider;
import net.stevechaloner.idea.ffs.io.FileSystem;
import org.jetbrains.annotations.NotNull;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Steve Chaloner
 */
public class ConfigForm
{
    /**
     * File descriptor for search plugin directory selection.
     */
    private static final FileChooserDescriptor FILE_CHOOSER_DESCRIPTOR = new FileChooserDescriptor(false,
                                                                                                   true,
                                                                                                   false,
                                                                                                   false,
                                                                                                   false,
                                                                                                   false);
    /**
     * Form bindings
     */
    private JTextField searchPluginsDirTF;
    private JPanel rootComponent;
    private JButton browseButton;
    private JTabbedPane tabbedPane1;
    private JButton addButton;
    private JButton removeButton;
    private JButton addAllButton;
    private JButton removeAllButton;
    private JList availableList;
    private JList selectedList;

    /**
     * List model for available search providers.
     */
    private final DefaultListModel availableListModel = new DefaultListModel();

    /**
     * List model for selected search providers.
     */
    private final DefaultListModel selectedListModel = new DefaultListModel();

    /**
     * Flag for list modification.
     */
    private boolean listModified = false;

    /**
     * Provider for search provider names.
     */
    private final SearchProviderProvider spp;

    /**
     * Initialises a new instance of this class.
     *
     * @param project the project
     * @param spp the provider for search providers
     */
    public ConfigForm(final @NotNull Project project,
                      @NotNull SearchProviderProvider spp)
    {
        this.spp = spp;

        availableList.setModel(availableListModel);
        selectedList.setModel(selectedListModel);

        browseButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                String path = searchPluginsDirTF.getText();
                VirtualFile existingSelection = null;
                if (!StringUtil.isEmptyOrSpaces(path))
                {
                    existingSelection = FileSystem.FILE.getFileSystem().findFileByPath(path);
                }
                VirtualFile[] files = FileChooser.chooseFiles(project,
                                                              FILE_CHOOSER_DESCRIPTOR,
                                                              existingSelection);
                if (files != null && files.length > 0)
                {
                    searchPluginsDirTF.setText(files[0].getPath());
                }
            }
        });
        addButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                slushboxMove(availableList,
                             availableListModel,
                             selectedListModel);
            }
        });
        removeButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                slushboxMove(selectedList,
                             selectedListModel,
                             availableListModel);
            }
        });
        addAllButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                slushboxMoveAll(availableListModel,
                                selectedListModel);
            }
        });
        removeAllButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                slushboxMoveAll(selectedListModel,
                                availableListModel);
            }
        });
        selectedListModel.addListDataListener(new ListDataListener()
        {

            public void intervalAdded(ListDataEvent e)
            {
                listModified = true;
            }

            public void intervalRemoved(ListDataEvent e)
            {
                listModified = true;
            }

            public void contentsChanged(ListDataEvent e)
            {
                listModified = true;
            }
        });
    }

    /**
     *
     * @param fromList source list
     * @param fromModel source model
     * @param toModel target model
     */
    private void slushboxMove(JList fromList,
                              DefaultListModel fromModel,
                              DefaultListModel toModel)
    {
        int[] indices = fromList.getSelectedIndices();
        if (indices.length > 0)
        {
            for (int i = 0; i < indices.length; i++)
            {
                Object o = fromModel.remove(indices[i] - i);
                toModel.addElement(o);
            }
        }
    }

    /**
     *
     * @param fromModel source model
     * @param toModel target model
     */
    private void slushboxMoveAll(DefaultListModel fromModel,
                                 DefaultListModel toModel)
    {
        for (Object o : fromModel.toArray())
        {
            toModel.addElement(o);
        }
        fromModel.clear();
    }

    // javadoc unnecessary
    public JComponent getRootComponent()
    {
        return rootComponent;
    }

    // javadoc unnecessary
    public void setData(Config config)
    {
        searchPluginsDirTF.setText(config.getSearchPluginsDirectory());
        List<String> selectedSearchProviders = config.getQuotedSearchProviders();
        selectedListModel.clear();
        for (String provider : selectedSearchProviders)
        {
            selectedListModel.addElement(provider);
        }
        availableListModel.clear();
        for (String s : spp.getSearchProviderNames())
        {
            if (!selectedListModel.contains(s))
            {
                availableListModel.addElement(s);
            }
        }
        listModified = false;
    }

    // javadoc unnecessary
    public void getData(Config config)
    {
        config.setSearchPluginsDirectory(searchPluginsDirTF.getText());
        List<String> selectedSearchProviders = new ArrayList<String>();
        Object[] objects = selectedListModel.toArray();
        String[] strings = new String[objects.length];
        System.arraycopy(objects, 0,
                         strings, 0,
                         objects.length);
        selectedSearchProviders.addAll(Arrays.asList(strings));
        config.setQuotedSearchProviders(selectedSearchProviders);
    }

    /**
     * Modification calculator.
     *
     * @param data the comparison data
     * @return true if the form has been modified
     */
    public boolean isModified(Config data)
    {
        return searchPluginsDirTF.getText() != null ? !searchPluginsDirTF.getText().equals(data.getSearchPluginsDirectory()) : data.getSearchPluginsDirectory() != null || listModified;
    }
}
